home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectPlay / AddressOverride / AddressOverride.cpp next >
C/C++ Source or Header  |  2001-10-31  |  56KB  |  1,343 lines

  1. //----------------------------------------------------------------------------
  2. // File: AddressOverride.cpp
  3. //
  4. // Desc: The main game file for the AddressOverride sample.  AddressOverride
  5. //       shows how to override the DirectPlay addressing in order to host or 
  6. //       connect to another session on the network.
  7. // 
  8. //       After a new game has started the sample begins a very simplistic 
  9. //       game called "The Greeting Game".  When two or more players are connected
  10. //       to the game, the players have the option of sending a single simple 
  11. //       DirectPlay message to all of the other players. When this message
  12. //       is receieved by the other players, they simply display a dialog box.
  13. //
  14. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. #define STRICT
  17. #include <winsock.h>
  18. #include <windows.h>
  19. #include <basetsd.h>
  20. #include <dplay8.h>
  21. #include <dplobby8.h>
  22. #include <dpaddr.h>
  23. #include <dxerr8.h>
  24. #include <tchar.h>
  25. #include <cguid.h>
  26. #include "DXUtil.h"
  27. #include "resource.h"
  28.  
  29.  
  30.  
  31.  
  32. //-----------------------------------------------------------------------------
  33. // Player context locking defines
  34. //-----------------------------------------------------------------------------
  35. CRITICAL_SECTION g_csPlayerContext;
  36. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  37. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  38. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  39. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  40.  
  41.  
  42. //-----------------------------------------------------------------------------
  43. // Defines, and constants
  44. //-----------------------------------------------------------------------------
  45. #define DPLAY_SAMPLE_KEY                TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  46. #define MAX_PLAYER_NAME                 14
  47. #define WM_APP_UPDATE_STATS             (WM_APP + 0)
  48. #define WM_APP_DISPLAY_WAVE             (WM_APP + 1)
  49. #define TIMER_WAIT_HOSTS_RESPONSE       (1)
  50.  
  51. // This GUID allows DirectPlay to find other instances of the same game on
  52. // the network.  So it must be unique for every game, and the same for 
  53. // every instance of that game.  // {02AE835D-9179-485f-8343-901D327CE794}
  54. GUID g_guidApp = { 0x2ae835d, 0x9179, 0x485f, { 0x83, 0x43, 0x90, 0x1d, 0x32, 0x7c, 0xe7, 0x94 } };
  55.  
  56. struct APP_PLAYER_INFO
  57. {
  58.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  59.                                             // are done w/ this object
  60.     DPNID dpnidPlayer;                      // DPNID of player
  61.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  62. };
  63.  
  64.  
  65.  
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Global variables
  69. //-----------------------------------------------------------------------------
  70. IDirectPlay8Peer*       g_pDP                         = NULL;    // DirectPlay peer object
  71. HINSTANCE               g_hInst                       = NULL;    // HINST of app
  72. HWND                    g_hDlg                        = NULL;    // HWND of main dialog
  73. DPNID                   g_dpnidLocalPlayer            = 0;       // DPNID of local player
  74. LONG                    g_lNumberOfActivePlayers      = 0;       // Number of players currently in game
  75. TCHAR                   g_strAppName[256]             = TEXT("AddressOverride");
  76. HRESULT                 g_hrDialog;                              // Exit code for app 
  77. TCHAR                   g_strLocalPlayerName[MAX_PATH];          // Local player name
  78. TCHAR                   g_strSessionName[MAX_PATH];              // Session name
  79. TCHAR                   g_strPreferredProvider[MAX_PATH];        // Provider string
  80.  
  81. BOOL                    g_bHostPlayer                 = FALSE;   // TRUE if local player is host
  82. GUID*                   g_pCurSPGuid                  = NULL;    // Currently selected guid
  83. TCHAR                   g_strLocalIP[100];                       // Local IP address
  84. HANDLE                  g_hConnectCompleteEvent       = NULL;    // Event signaled when connection complete
  85. HRESULT                 g_hrConnectComplete           = S_OK;    // Status of connection when it completes
  86. HANDLE                  g_hEnumHostEvent              = NULL;    // Event signaled when the first session is enum
  87. DPNHANDLE               g_hEnumAsyncOp                = NULL;    // Async handle for enuming hosts
  88. DPN_APPLICATION_DESC*   g_pEnumedSessionAppDesc       = NULL;    // App desc of first session enumed
  89. IDirectPlay8Address*    g_pEnumedSessionHostAddr      = NULL;    // Host addr of first session enumed
  90. IDirectPlay8Address*    g_pEnumedSessionDeviceAddr    = NULL;    // Address of device to use
  91.  
  92.  
  93. //-----------------------------------------------------------------------------
  94. // App specific DirectPlay messages and structures 
  95. //-----------------------------------------------------------------------------
  96. #define GAME_MSGID_WAVE        1
  97.  
  98. // Change compiler pack alignment to be BYTE aligned, and pop the current value
  99. #pragma pack( push, 1 )
  100.  
  101. struct GAMEMSG_GENERIC
  102. {
  103.     DWORD dwType;
  104. };
  105.  
  106. // Pop the old pack alignment
  107. #pragma pack( pop )
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Function-prototypes
  113. //-----------------------------------------------------------------------------
  114. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  115. INT_PTR CALLBACK OverrideDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  116. INT_PTR CALLBACK GreetingDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  117. HRESULT          InitDirectPlay();
  118. HRESULT          OnInitOverrideDialog( HWND hDlg );
  119. VOID             SetupAddressFields( HWND hDlg );
  120. HRESULT          EnumServiceProviders( HWND hDlg );
  121. HRESULT          EnumAdapters( HWND hDlg, GUID* pSPGuid );
  122. HRESULT          LaunchMultiplayerGame( HWND hDlg );
  123. HRESULT          WaveToAllPlayers();
  124. VOID             AppendTextToEditControl( HWND hDlg, TCHAR* strNewLogLine );
  125.  
  126.  
  127.  
  128.  
  129. //-----------------------------------------------------------------------------
  130. // Name: WinMain()
  131. // Desc: Entry point for the application.  Since we use a simple dialog for 
  132. //       user interaction we don't need to pump messages.
  133. //-----------------------------------------------------------------------------
  134. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, 
  135.                       LPSTR pCmdLine, INT nCmdShow )
  136. {
  137.     HRESULT hr;
  138.     HKEY    hDPlaySampleRegKey;
  139.     BOOL    bConnectSuccess = FALSE;
  140.  
  141.     g_hInst = hInst; 
  142.     InitializeCriticalSection( &g_csPlayerContext );
  143.     g_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 
  144.     g_hEnumHostEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 
  145.  
  146.     // Read persistent state information from registry
  147.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  148.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  149.                     &hDPlaySampleRegKey, NULL );
  150.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  151.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  152.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  153.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  154.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  155.                              g_strPreferredProvider, MAX_PATH, 
  156.                              TEXT("DirectPlay8 TCP/IP Service Provider") );
  157.  
  158.     // Init COM so we can use CoCreateInstance
  159.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  160.  
  161.     if( FAILED( hr = InitDirectPlay() ) )
  162.     {
  163.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  164.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  165.                     TEXT("The sample will now quit."),
  166.                     g_strAppName, MB_OK | MB_ICONERROR );
  167.         return FALSE;
  168.     }
  169.  
  170.     // Connect or host a DirectPlay session.  Pop UI to query 
  171.     // for addressing so that DirectPlay's default dialogs are overridden
  172.     g_hrDialog = S_OK;
  173.     DialogBox( g_hInst, MAKEINTRESOURCE(IDD_ADDRESS_OVERRIDE), NULL, 
  174.                (DLGPROC) OverrideDlgProc );
  175.     
  176.     if( FAILED( g_hrDialog ) ) 
  177.     {
  178.         DXTRACE_ERR( TEXT("ConnectUsingOverrideDlg"), g_hrDialog );
  179.         MessageBox( NULL, TEXT("Multiplayer connect failed. ")
  180.                     TEXT("The sample will now quit."),
  181.                     g_strAppName, MB_OK | MB_ICONERROR );
  182.         bConnectSuccess = FALSE;
  183.     } 
  184.     else if( g_hrDialog == S_FALSE ) 
  185.     {
  186.         // The user canceled the connect dialog, so quit 
  187.         bConnectSuccess = FALSE;
  188.     }
  189.     else
  190.     {
  191.         bConnectSuccess = TRUE; 
  192.  
  193.         // Write information to the registry
  194.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  195.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  196.         DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  197.     }
  198.  
  199.     if( bConnectSuccess )
  200.     {
  201.         // App is now connected via DirectPlay, so start the game.  
  202.  
  203.         // For this sample, we just start a simple dialog box game.
  204.         g_hrDialog = S_OK;
  205.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, 
  206.                    (DLGPROC) GreetingDlgProc );
  207.  
  208.         if( FAILED( g_hrDialog ) )
  209.         {
  210.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  211.             {
  212.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  213.                             TEXT("The sample will now quit."),
  214.                             g_strAppName, MB_OK | MB_ICONERROR );
  215.             }
  216.             else
  217.             {
  218.                 DXTRACE_ERR( TEXT("DialogBox"), g_hrDialog );
  219.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  220.                             TEXT("The sample will now quit."),
  221.                             g_strAppName, MB_OK | MB_ICONERROR );
  222.             }
  223.         }
  224.     }
  225.  
  226.     if( g_pDP )
  227.     {
  228.         g_pDP->Close(0);
  229.         SAFE_RELEASE( g_pDP );
  230.     }
  231.  
  232.     RegCloseKey( hDPlaySampleRegKey );
  233.     DeleteCriticalSection( &g_csPlayerContext );
  234.     CloseHandle( g_hEnumHostEvent );
  235.     CloseHandle( g_hConnectCompleteEvent );
  236.     CoUninitialize();
  237.  
  238.     return TRUE;
  239. }
  240.  
  241.  
  242.  
  243.  
  244. //-----------------------------------------------------------------------------
  245. // Name: InitDirectPlay()
  246. // Desc: 
  247. //-----------------------------------------------------------------------------
  248. HRESULT InitDirectPlay()
  249. {
  250.     HRESULT hr;
  251.  
  252.     // Create IDirectPlay8Peer
  253.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  254.                                        CLSCTX_INPROC_SERVER,
  255.                                        IID_IDirectPlay8Peer, 
  256.                                        (LPVOID*) &g_pDP ) ) )
  257.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  258.  
  259.     // Init IDirectPlay8Peer
  260.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  261.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  262.  
  263.     return S_OK;
  264. }
  265.  
  266.  
  267.  
  268.  
  269. //-----------------------------------------------------------------------------
  270. // Name: OverrideDlgProc()
  271. // Desc: Handles dialog messages
  272. //-----------------------------------------------------------------------------
  273. INT_PTR CALLBACK OverrideDlgProc( HWND hDlg, UINT msg, 
  274.                                   WPARAM wParam, LPARAM lParam )
  275. {
  276.     HRESULT hr;
  277.  
  278.     switch( msg ) 
  279.     {
  280.         case WM_INITDIALOG:
  281.         {
  282.             g_hDlg = hDlg;
  283.             if( FAILED( hr = OnInitOverrideDialog( hDlg ) ) )
  284.             {
  285.                 DXTRACE_ERR( TEXT("OnInitDialog"), hr );
  286.                 MessageBox( NULL, TEXT("Failed initializing dialog box. ")
  287.                             TEXT("The sample will now quit."),
  288.                             g_strAppName, MB_OK | MB_ICONERROR );
  289.                 EndDialog( hDlg, 0 );
  290.             }
  291.             break;
  292.         }
  293.  
  294.         case WM_COMMAND:
  295.         {
  296.             switch( LOWORD(wParam) )
  297.             {
  298.                 case IDC_HOST_SESSION:
  299.                     SetupAddressFields( hDlg );
  300.                     break;
  301.  
  302.                 case IDC_SP_COMBO:
  303.                 {
  304.                     // If the pSPGuid changed then re-enum the adapters, and
  305.                     // update the address fields.
  306.                     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  307.                     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  308.                     if( pSPGuid != NULL && g_pCurSPGuid != pSPGuid )
  309.                     {
  310.                         g_pCurSPGuid = pSPGuid;
  311.                         SetupAddressFields( hDlg );
  312.                         EnumAdapters( hDlg, pSPGuid );
  313.                     }
  314.                     break;
  315.                 }
  316.  
  317.                 case IDOK:
  318.                     if( FAILED( g_hrDialog = LaunchMultiplayerGame( hDlg ) ) )
  319.                     {
  320.                         if( g_hrDialog == DPNERR_ADDRESSING )
  321.                         {
  322.                             // This will be returned if the ip address is invalid
  323.                             MessageBox( hDlg, TEXT("IP address not valid."),
  324.                                         g_strAppName, MB_OK );
  325.                         }
  326.                         else if( g_hrDialog == DPNERR_INVALIDDEVICEADDRESS )
  327.                         {
  328.                             // This will be returned if the user canceled the dialog
  329.                             MessageBox( hDlg, TEXT("User cancelled the DirectPlay dialog."),
  330.                                         g_strAppName, MB_OK );
  331.                         }
  332.                         else
  333.                         {
  334.                             DXTRACE_ERR( TEXT("LaunchMultiplayerGame"), g_hrDialog );
  335.                             MessageBox( NULL, TEXT("Failed to launch game. "),
  336.                                         g_strAppName, MB_OK | MB_ICONERROR );                        
  337.                         }
  338.                     }
  339.                     break;
  340.  
  341.                 case IDCANCEL:
  342.                     g_hrDialog = S_FALSE;
  343.                     EndDialog( hDlg, 0 );
  344.                     break;
  345.             }
  346.             break;
  347.         }
  348.  
  349.         case WM_TIMER:
  350.             if( wParam == TIMER_WAIT_HOSTS_RESPONSE )
  351.             {
  352.                 DWORD dwResult;
  353.                 
  354.                 dwResult = WaitForSingleObject( g_hEnumHostEvent, 0 );
  355.                 if( dwResult == WAIT_OBJECT_0 )
  356.                 {
  357.                     // Connect to host that was found. There should only be on device address in
  358.                     // the connection settings structure when connecting to a session, so just 
  359.                     // pass in the first one.  
  360.                     // The enumeration is automatically cancelled after Connect is called 
  361.                     DPNHANDLE hAsync;
  362.                     hr = g_pDP->Connect( g_pEnumedSessionAppDesc,      // the application desc
  363.                                          g_pEnumedSessionHostAddr,     // address of the host of the session
  364.                                          g_pEnumedSessionDeviceAddr,   // address of the local device used to connect to the host
  365.                                          NULL, NULL,                   // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  366.                                          NULL, 0,                      // user data, user data size
  367.                                          NULL,                         // player context,
  368.                                          NULL, &hAsync,                // async context, async handle,
  369.                                          0 );                          // flags
  370.                     if( FAILED(hr) )
  371.                         return DXTRACE_ERR( TEXT("Connect"), hr );
  372.  
  373.                     // Wait until the MessageHandler sets an event to tell us the 
  374.                     // DPN_MSGID_CONNECT_COMPLETE has been processed.  Then 
  375.                     // m_hrConnectComplete will be valid.
  376.                     WaitForSingleObject( g_hConnectCompleteEvent, INFINITE );
  377.  
  378.                     if( FAILED( g_hrConnectComplete ) )
  379.                     {
  380.                         DXTRACE_ERR( TEXT("DPN_MSGID_CONNECT_COMPLETE"), g_hrConnectComplete );
  381.                         MessageBox( hDlg, TEXT("Unable to join game."),
  382.                                     g_strAppName, MB_OK | MB_ICONERROR );
  383.                         hr = g_hrConnectComplete;
  384.                     }
  385.  
  386.                     if( g_pEnumedSessionAppDesc )
  387.                     {
  388.                         SAFE_DELETE_ARRAY( g_pEnumedSessionAppDesc->pwszSessionName );
  389.                         SAFE_DELETE_ARRAY( g_pEnumedSessionAppDesc );
  390.                     }
  391.                     SAFE_RELEASE( g_pEnumedSessionHostAddr );                    
  392.                     SAFE_RELEASE( g_pEnumedSessionDeviceAddr );
  393.  
  394.                     EndDialog( g_hDlg, 0 );
  395.                 }
  396.             }
  397.             break;
  398.  
  399.         case WM_DESTROY:
  400.         {
  401.             GetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName, MAX_PATH );
  402.             GetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName, MAX_PATH );
  403.             int nIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  404.             SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETLBTEXT, nIndex, (LPARAM) g_strPreferredProvider );
  405.  
  406.             int nCount,i;
  407.             nCount = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCOUNT, 0, 0 );
  408.             for( i=0; i<nCount; i++ )
  409.             {
  410.                 GUID* pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, i, 0 );
  411.                 SAFE_DELETE( pGuid );
  412.             }
  413.  
  414.             nCount = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCOUNT, 0, 0 );
  415.             for( i=0; i<nCount; i++ )
  416.             {
  417.                 GUID* pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, 
  418.                                                            CB_GETITEMDATA, i, 0 );
  419.                 SAFE_DELETE( pGuid );
  420.             }            
  421.             break;
  422.         }
  423.     }
  424.  
  425.     return FALSE; // Didn't handle message
  426. }
  427.  
  428.  
  429.  
  430.  
  431. //-----------------------------------------------------------------------------
  432. // Name: OnInitOverrideDialog
  433. // Desc: 
  434. //-----------------------------------------------------------------------------
  435. HRESULT OnInitOverrideDialog( HWND hDlg )
  436. {
  437.     HRESULT hr;
  438.  
  439.     // Load and set the icon
  440.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  441.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  442.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  443.  
  444.     CheckDlgButton( hDlg, IDC_HOST_SESSION, BST_CHECKED );
  445.  
  446.     SetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName );
  447.     SetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName );
  448.  
  449.     if( FAILED( hr = EnumServiceProviders( hDlg ) ) )
  450.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  451.     
  452.     WSADATA WSAData;
  453.     _tcscpy( g_strLocalIP, TEXT("") );
  454.     if( WSAStartup (MAKEWORD(1,0), &WSAData) == 0) 
  455.     {
  456.         CHAR strLocalHostName[MAX_PATH];
  457.         gethostname( strLocalHostName, MAX_PATH );
  458.         HOSTENT* pHostEnt = gethostbyname( strLocalHostName );
  459.         if( pHostEnt )
  460.         {
  461.             in_addr* pInAddr = (in_addr*) pHostEnt->h_addr_list[0];
  462.             char* strLocalIP = inet_ntoa( *pInAddr );
  463.             if( strLocalIP )
  464.                 DXUtil_ConvertAnsiStringToGeneric( g_strLocalIP, strLocalIP );
  465.         }
  466.  
  467.         WSACleanup();
  468.     }
  469.     SetDlgItemText( hDlg, IDC_LOCAL_IP, g_strLocalIP );
  470.     
  471.     SetupAddressFields( hDlg );
  472.  
  473.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  474.     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  475.     if( pSPGuid != NULL )
  476.     {
  477.         g_pCurSPGuid = pSPGuid;
  478.         EnumAdapters( hDlg, pSPGuid );
  479.     }
  480.  
  481.     return S_OK;
  482. }
  483.  
  484.  
  485.  
  486.  
  487.  
  488. //-----------------------------------------------------------------------------
  489. // Name: SetupAddressFields
  490. // Desc: Based on the SP selected, update the address UI 
  491. //-----------------------------------------------------------------------------
  492. VOID SetupAddressFields( HWND hDlg )
  493. {
  494.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  495.     if( nSPIndex == LB_ERR )
  496.         return;
  497.     GUID* pGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  498.     if( pGuid == NULL )
  499.         return;
  500.  
  501.     BOOL bHosting = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
  502.  
  503.     if( *pGuid == CLSID_DP8SP_TCPIP )
  504.     {
  505.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), TRUE );
  506.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  507.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), TRUE );
  508.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("Port:") );
  509.  
  510.         if( bHosting )
  511.         {
  512.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  513.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  514.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  515.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  516.         }
  517.         else
  518.         {
  519.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
  520.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  521.             EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
  522.             SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("IP Address:") );
  523.         }
  524.     }
  525.     else if( *pGuid == CLSID_DP8SP_MODEM )
  526.     {
  527.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
  528.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  529.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
  530.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("Phone Number:") );
  531.  
  532.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
  533.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  534.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
  535.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
  536.     }
  537.     else if( *pGuid == CLSID_DP8SP_IPX )
  538.     {
  539.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  540.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  541.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  542.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  543.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), TRUE );
  544.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  545.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), TRUE );
  546.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("Port:") );
  547.     }
  548.     else 
  549.     {
  550.         // CLSID_DP8SP_SERIAL or unknown so disable all the address lines 
  551.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
  552.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
  553.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
  554.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
  555.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
  556.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
  557.         EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
  558.         SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
  559.     }
  560. }
  561.  
  562.  
  563.  
  564.  
  565. //-----------------------------------------------------------------------------
  566. // Name: EnumServiceProviders()
  567. // Desc: Fills the combobox with service providers
  568. //-----------------------------------------------------------------------------
  569. HRESULT EnumServiceProviders( HWND hDlg )
  570. {
  571.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
  572.     HRESULT hr;
  573.     DWORD   dwItems = 0;
  574.     DWORD   dwSize  = 0;
  575.     int     nIndex;
  576.  
  577.     // Enumerate all DirectPlay service providers, and store them in the listbox
  578.     hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
  579.                                       &dwItems, 0 );
  580.     if( hr != DPNERR_BUFFERTOOSMALL )
  581.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  582.  
  583.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  584.     if( FAILED( hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
  585.                                                   &dwSize, &dwItems, 0 ) ) )
  586.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  587.  
  588.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  589.     for ( DWORD i = 0; i < dwItems; i++ )
  590.     {
  591.         TCHAR strName[MAX_PATH];
  592.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  593.  
  594.         // Found a service provider, so put it in the listbox
  595.         nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_ADDSTRING, 
  596.                                               0, (LPARAM) strName );
  597.  
  598.         // Store pointer to GUID in listbox
  599.         GUID* pGuid = new GUID;
  600.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  601.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETITEMDATA, 
  602.                             nIndex, (LPARAM) pGuid );
  603.  
  604.         pdnSPInfoEnum++;
  605.     }
  606.  
  607.     SAFE_DELETE_ARRAY( pdnSPInfo );
  608.  
  609.     // Try to select the default preferred provider
  610.     nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1,
  611.                                       (LPARAM)g_strPreferredProvider );
  612.     if( nIndex != LB_ERR )
  613.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, nIndex, 0 );
  614.     else
  615.         SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, 0, 0 );
  616.  
  617.     return S_OK;
  618. }
  619.  
  620.  
  621.  
  622.  
  623. //-----------------------------------------------------------------------------
  624. // Name: EnumAdapters()
  625. // Desc: Fills the combobox with adapters for a specified SP
  626. //-----------------------------------------------------------------------------
  627. HRESULT EnumAdapters( HWND hDlg, GUID* pSPGuid )
  628. {
  629.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
  630.     TCHAR   strName[MAX_PATH];
  631.     HRESULT hr;
  632.     DWORD   dwItems = 0;
  633.     DWORD   dwSize  = 0;
  634.     int     nIndex;
  635.     int     nAllAdaptersIndex = 0;
  636.  
  637.     SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_RESETCONTENT, 0, 0 );
  638.  
  639.     // Enumerate all DirectPlay service providers, and store them in the listbox
  640.     hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo, &dwSize,
  641.                                       &dwItems, 0 );
  642.     if( SUCCEEDED(hr) ) // No adapters found
  643.         return S_OK;
  644.  
  645.     if( hr != DPNERR_BUFFERTOOSMALL )
  646.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  647.  
  648.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  649.     if( FAILED( hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo,
  650.                                                   &dwSize, &dwItems, 0 ) ) )
  651.         return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
  652.  
  653.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
  654.     for ( DWORD i = 0; i < dwItems; i++ )
  655.     {
  656.         DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
  657.  
  658.         // Found a service provider, so put it in the listbox
  659.         nIndex = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_ADDSTRING, 
  660.                                           0, (LPARAM) strName );
  661.  
  662.         if( _tcscmp( strName, TEXT("All Adapters") ) == 0 )
  663.             nAllAdaptersIndex = nIndex;
  664.  
  665.         // Store pointer to GUID in listbox
  666.         GUID* pGuid = new GUID;
  667.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  668.  
  669.         SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETITEMDATA, 
  670.                             nIndex, (LPARAM) pGuid );
  671.  
  672.         pdnSPInfoEnum++;
  673.     }
  674.  
  675.     SAFE_DELETE_ARRAY( pdnSPInfo );
  676.  
  677.     SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETCURSEL, nAllAdaptersIndex, 0 );
  678.  
  679.     return S_OK;
  680. }
  681.  
  682.  
  683.  
  684.  
  685. //-----------------------------------------------------------------------------
  686. // Name: LaunchMultiplayerGame
  687. // Desc: 
  688. //-----------------------------------------------------------------------------
  689. HRESULT LaunchMultiplayerGame( HWND hDlg ) 
  690. {
  691.     HRESULT hr;
  692.  
  693.     g_bHostPlayer = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
  694.     IDirectPlay8Address* pHostAddress     = NULL;
  695.     IDirectPlay8Address* pDeviceAddress   = NULL;
  696.     BOOL bOkToQuery = FALSE;
  697.  
  698.     int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
  699.     GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
  700.  
  701.     if( !g_bHostPlayer )
  702.     {
  703.         // Create a host address if connecting to a host, 
  704.         // otherwise keep it as NULL
  705.         if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, 
  706.                                            IID_IDirectPlay8Address, (void **) &pHostAddress ) ) )
  707.             return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  708.  
  709.         // Set the SP to pHostAddress
  710.         if( FAILED( hr = pHostAddress->SetSP( pSPGuid ) ) )
  711.             return DXTRACE_ERR( TEXT("SetSP"), hr );
  712.     }
  713.  
  714.     // Create a device address to specify which device we are using 
  715.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, 
  716.                                        IID_IDirectPlay8Address, (void **) &pDeviceAddress ) ) )
  717.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  718.  
  719.     // Set the SP to pDeviceAddress
  720.     if( FAILED( hr = pDeviceAddress->SetSP( pSPGuid ) ) )
  721.         return DXTRACE_ERR( TEXT("SetSP"), hr );
  722.  
  723.     // Add the adapter to pHostAddress
  724.     int nAdapterIndex = (int) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCURSEL, 0, 0 );
  725.     GUID* pAdapterGuid = NULL;
  726.  
  727.     if( nAdapterIndex != CB_ERR )
  728.     {
  729.         GUID* pAdapterGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETITEMDATA, 
  730.                                                          nAdapterIndex, 0 );
  731.         if( FAILED( hr = pDeviceAddress->SetDevice( pAdapterGuid ) ) )
  732.             return DXTRACE_ERR( TEXT("SetDevice"), hr );
  733.     }
  734.  
  735.     if( *pSPGuid == CLSID_DP8SP_TCPIP )
  736.     {
  737.         TCHAR strIP[MAX_PATH];
  738.         TCHAR strPort[MAX_PATH];
  739.  
  740.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strIP, MAX_PATH );
  741.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE2, strPort, MAX_PATH );
  742.  
  743.         if( g_bHostPlayer )
  744.         {
  745.             if( _tcslen( strPort ) > 0 )
  746.             {
  747.                 // Add the port to pDeviceAddress
  748.                 DWORD dwPort = _ttoi( strPort );
  749.                 if( FAILED( hr = pDeviceAddress->AddComponent( DPNA_KEY_PORT, 
  750.                                                                &dwPort, sizeof(dwPort),
  751.                                                                DPNA_DATATYPE_DWORD ) ) )
  752.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  753.             }
  754.         }
  755.         else
  756.         {
  757.             // Add the IP address to pHostAddress
  758.             if( _tcslen( strIP ) > 0 )
  759.             {
  760.                 WCHAR wstrIP[MAX_PATH];
  761.                 DXUtil_ConvertGenericStringToWide( wstrIP, strIP );
  762.  
  763.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_HOSTNAME, 
  764.                                                              wstrIP, (wcslen(wstrIP)+1)*sizeof(WCHAR), 
  765.                                                              DPNA_DATATYPE_STRING ) ) )
  766.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  767.             }
  768.  
  769.             if( _tcslen( strPort ) > 0 )
  770.             {
  771.                 // Add the port to pHostAddress
  772.                 DWORD dwPort = _ttoi( strPort );
  773.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PORT, 
  774.                                                              &dwPort, sizeof(dwPort),
  775.                                                              DPNA_DATATYPE_DWORD ) ) )
  776.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  777.             }
  778.         }
  779.     }
  780.     else if( *pSPGuid == CLSID_DP8SP_IPX )
  781.     {
  782.         TCHAR strPort[MAX_PATH];
  783.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE2, strPort, MAX_PATH );
  784.  
  785.         if( g_bHostPlayer )
  786.         {
  787.             if( _tcslen( strPort ) > 0 )
  788.             {
  789.                 // Add the port to pDeviceAddress
  790.                 DWORD dwPort = _ttoi( strPort );
  791.                 if( FAILED( hr = pDeviceAddress->AddComponent( DPNA_KEY_PORT, 
  792.                                                                &dwPort, sizeof(dwPort),
  793.                                                                DPNA_DATATYPE_DWORD ) ) )
  794.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  795.             }
  796.         }
  797.         else
  798.         {
  799.             if( _tcslen( strPort ) > 0 )
  800.             {
  801.                 // Add the port to pHostAddress
  802.                 DWORD dwPort = _ttoi( strPort );
  803.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PORT, 
  804.                                                              &dwPort, sizeof(dwPort),
  805.                                                              DPNA_DATATYPE_DWORD ) ) )
  806.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  807.             }
  808.         }
  809.     }
  810.     else if( *pSPGuid == CLSID_DP8SP_MODEM )
  811.     {
  812.         TCHAR strPhone[MAX_PATH];
  813.         GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strPhone, MAX_PATH );
  814.  
  815.         if( !g_bHostPlayer )
  816.         {
  817.             // Add the phonenumber to pHostAddress
  818.             if( _tcslen( strPhone ) > 0 )
  819.             {
  820.                 WCHAR wstrPhone[MAX_PATH];
  821.                 DXUtil_ConvertGenericStringToWide( wstrPhone, strPhone );
  822.  
  823.                 if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PHONENUMBER, 
  824.                                                              wstrPhone, (wcslen(wstrPhone)+1)*sizeof(WCHAR), 
  825.                                                              DPNA_DATATYPE_STRING ) ) )
  826.                     return DXTRACE_ERR( TEXT("AddComponent"), hr );
  827.             }
  828.         }
  829.     }
  830.     else if( *pSPGuid == CLSID_DP8SP_SERIAL )
  831.     {
  832.         // This simple client doesn't have UI to query for the various
  833.         // fields needed for the serial.  So we just let DPlay popup a dialog
  834.         // to ask the user which settings are needed.
  835.         bOkToQuery = TRUE;
  836.     }
  837.     else
  838.     {
  839.         // Unknown SP, so leave as is
  840.         bOkToQuery = TRUE;
  841.     }
  842.  
  843.     DPN_APPLICATION_DESC dpnAppDesc;
  844.     ZeroMemory( &dpnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  845.     dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
  846.     dpnAppDesc.guidApplication = g_guidApp;
  847.     dpnAppDesc.guidInstance    = GUID_NULL;
  848.  
  849.     // Set the peer info
  850.     WCHAR wszPeerName[MAX_PATH];
  851.     DXUtil_ConvertGenericStringToWide( wszPeerName, g_strLocalPlayerName );
  852.     DPN_PLAYER_INFO dpPlayerInfo;
  853.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  854.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  855.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  856.     dpPlayerInfo.pwszName = wszPeerName;
  857.  
  858.     // Set the peer info, and use the DPNOP_SYNC since by default this
  859.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  860.     // be set by the time we call Connect() below.
  861.     if( FAILED( hr = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  862.         return DXTRACE_ERR( TEXT("SetPeerInfo"), hr );
  863.  
  864.     if( g_bHostPlayer )
  865.     {
  866.         // Set the dpnAppDesc.pwszSessionName
  867.         TCHAR strSessionName[MAX_PATH];
  868.         GetDlgItemText( hDlg, IDC_SESSION_NAME, strSessionName, MAX_PATH );
  869.         if( _tcslen( strSessionName ) == 0 )
  870.         {
  871.             dpnAppDesc.pwszSessionName = NULL;
  872.         }
  873.         else
  874.         {
  875.             WCHAR wstrSessionName[MAX_PATH];
  876.             DXUtil_ConvertGenericStringToWide( wstrSessionName, strSessionName );
  877.             dpnAppDesc.pwszSessionName = new WCHAR[wcslen(wstrSessionName)+1];
  878.             wcscpy( dpnAppDesc.pwszSessionName, wstrSessionName );
  879.         }
  880.  
  881.         // Host a game as described by pSettings
  882.         hr = g_pDP->Host( &dpnAppDesc,          // the application desc
  883.                           &pDeviceAddress,    // array of addresses of the local devices used to connect to the host
  884.                           1,                    // number in array
  885.                           NULL, NULL,           // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  886.                           NULL,                 // player context
  887.                           bOkToQuery );                 // flags
  888.  
  889.         SAFE_DELETE_ARRAY( dpnAppDesc.pwszSessionName );
  890.         SAFE_RELEASE( pDeviceAddress );
  891.  
  892.         if( FAILED(hr) )
  893.         {
  894.             SAFE_RELEASE( pHostAddress );
  895.             SAFE_RELEASE( pDeviceAddress );
  896.  
  897.             if( hr == DPNERR_INVALIDDEVICEADDRESS )  // This will be returned if the user canceled the dplay query dlg
  898.                 return hr;                
  899.             return DXTRACE_ERR( TEXT("Host"), hr );    
  900.         }
  901.  
  902.         EndDialog( g_hDlg, 0 );
  903.     }
  904.     else
  905.     {
  906.         // Query for the enum host timeout for this SP
  907.         DPN_SP_CAPS dpspCaps;
  908.         ZeroMemory( &dpspCaps, sizeof(DPN_SP_CAPS) );
  909.         dpspCaps.dwSize = sizeof(DPN_SP_CAPS);
  910.         if( FAILED( hr = g_pDP->GetSPCaps( pSPGuid, &dpspCaps, 0 ) ) )
  911.             return DXTRACE_ERR( TEXT("GetSPCaps"), hr );
  912.  
  913.         // Set the host expire time to around 3 times 
  914.         // length of the dwDefaultEnumRetryInterval
  915.         DWORD dwEnumHostTimeout = dpspCaps.dwDefaultEnumRetryInterval * 3;
  916.  
  917.         // Enumerate hosts
  918.         DPN_APPLICATION_DESC    dnAppDesc;
  919.         ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  920.         dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  921.         dnAppDesc.guidApplication = g_guidApp;
  922.  
  923.         // Enumerate all the active DirectPlay games on the selected connection
  924.         hr = g_pDP->EnumHosts( &dnAppDesc,                            // application description
  925.                                pHostAddress,                          // host address
  926.                                pDeviceAddress,                        // device address
  927.                                NULL,                                  // pointer to user data
  928.                                0,                                     // user data size
  929.                                0,                                     // retry count (0=default)
  930.                                0,                                     // retry interval (0=default)
  931.                                dwEnumHostTimeout,                     // time out (forever)
  932.                                NULL,                                  // user context
  933.                                &g_hEnumAsyncOp,                       // async handle
  934.                                bOkToQuery                             // flags
  935.                                );
  936.         if( FAILED(hr) )
  937.         {
  938.             SAFE_RELEASE( pHostAddress );
  939.             SAFE_RELEASE( pDeviceAddress );
  940.  
  941.             if( hr == DPNERR_ADDRESSING )  // This will be returned if the ip address is invalid
  942.                 return hr;                 // For example, something like "asdf" 
  943.             if( hr == DPNERR_INVALIDDEVICEADDRESS )  // This will be returned if the user canceled the dplay query dlg
  944.                 return hr;                
  945.             return DXTRACE_ERR( TEXT("EnumHosts"), hr );
  946.         }
  947.  
  948.         SetTimer( g_hDlg, TIMER_WAIT_HOSTS_RESPONSE, 100, NULL );
  949.     }
  950.  
  951.     // Cleanup the addresses
  952.     SAFE_RELEASE( pHostAddress );
  953.     SAFE_RELEASE( pDeviceAddress );
  954.     
  955.     return S_OK;
  956. }
  957.  
  958.  
  959.  
  960.  
  961. //-----------------------------------------------------------------------------
  962. // Name: GreetingDlgProc()
  963. // Desc: Handles dialog messages
  964. //-----------------------------------------------------------------------------
  965. INT_PTR CALLBACK GreetingDlgProc( HWND hDlg, UINT msg, 
  966.                                   WPARAM wParam, LPARAM lParam )
  967. {
  968.     switch( msg ) 
  969.     {
  970.         case WM_INITDIALOG:
  971.         {
  972.             g_hDlg = hDlg;
  973.  
  974.             // Load and set the icon
  975.             HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  976.             SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  977.             SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  978.  
  979.             if( g_bHostPlayer )
  980.                 SetWindowText( hDlg, TEXT("AddressOverride (Host)") );
  981.             else
  982.                 SetWindowText( hDlg, TEXT("AddressOverride") );
  983.  
  984.             // Display local player's name
  985.             SetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strLocalPlayerName );
  986.  
  987.             PostMessage( hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  988.             break;
  989.         }
  990.  
  991.         case WM_APP_UPDATE_STATS:
  992.         {
  993.             // Update the number of players in the game
  994.             TCHAR strNumberPlayers[32];
  995.  
  996.             wsprintf( strNumberPlayers, TEXT("%d"), g_lNumberOfActivePlayers );
  997.             SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  998.             break;
  999.         }
  1000.  
  1001.         case WM_APP_DISPLAY_WAVE:
  1002.         {
  1003.             HRESULT          hr;
  1004.             DPNID            dpnidPlayer = (DWORD)wParam;
  1005.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  1006.             
  1007.             PLAYER_LOCK(); // enter player context CS
  1008.  
  1009.             // Get the player context accosicated with this DPNID
  1010.             hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  1011.                                           (LPVOID* const) &pPlayerInfo,
  1012.                                           0);
  1013.  
  1014.             PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  1015.             PLAYER_UNLOCK(); // leave player context CS
  1016.  
  1017.             if( FAILED(hr) || pPlayerInfo == NULL )
  1018.             {
  1019.                 // The player who sent this may have gone away before this 
  1020.                 // message was handled, so just ignore it
  1021.                 break;
  1022.             }
  1023.             
  1024.             // Make wave message and display it.
  1025.             TCHAR szWaveMessage[MAX_PATH];
  1026.             wsprintf( szWaveMessage, TEXT("%s just waved at you, %s!\r\n"), 
  1027.                       pPlayerInfo->strPlayerName, g_strLocalPlayerName );
  1028.  
  1029.             PLAYER_LOCK();
  1030.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1031.             PLAYER_UNLOCK();
  1032.  
  1033.             AppendTextToEditControl( hDlg, szWaveMessage );
  1034.             break;
  1035.         }
  1036.  
  1037.         case WM_COMMAND:
  1038.         {
  1039.             switch( LOWORD(wParam) )
  1040.             {
  1041.                 case IDC_WAVE:
  1042.                     if( FAILED( g_hrDialog = WaveToAllPlayers() ) )
  1043.                     {
  1044.                         DXTRACE_ERR( TEXT("WaveToAllPlayers"), g_hrDialog );
  1045.                         EndDialog( hDlg, 0 );
  1046.                     }
  1047.  
  1048.                     return TRUE;
  1049.  
  1050.                 case IDCANCEL:
  1051.                     g_hrDialog = S_OK;
  1052.                     EndDialog( hDlg, 0 );
  1053.                     return TRUE;
  1054.             }
  1055.             break;
  1056.         }
  1057.     }
  1058.  
  1059.     return FALSE; // Didn't handle message
  1060. }
  1061.  
  1062.  
  1063.  
  1064.  
  1065. //-----------------------------------------------------------------------------
  1066. // Name: DirectPlayMessageHandler
  1067. // Desc: Handler for DirectPlay messages.  This function is called by
  1068. //       the DirectPlay message handler pool of threads, so be careful of thread
  1069. //       synchronization problems with shared memory
  1070. //-----------------------------------------------------------------------------
  1071. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  1072.                                          DWORD dwMessageId, 
  1073.                                          PVOID pMsgBuffer )
  1074. {
  1075.     // Try not to stay in this message handler for too long, otherwise
  1076.     // there will be a backlog of data.  The best solution is to 
  1077.     // queue data as it comes in, and then handle it on other threads.
  1078.     
  1079.     // This function is called by the DirectPlay message handler pool of 
  1080.     // threads, so be careful of thread synchronization problems with shared memory
  1081.  
  1082.     switch( dwMessageId )
  1083.     {
  1084.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  1085.         {
  1086.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
  1087.             pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
  1088.  
  1089.             // This simple sample only records the 
  1090.             // first enum responce, and connects to that host
  1091.             if( NULL == g_pEnumedSessionHostAddr )
  1092.             {
  1093.                 // Duplicate pEnumHostsResponseMsg->pAddressSender in g_pEnumedSessionHostAddr.
  1094.                 if( pEnumHostsResponseMsg->pAddressSender )
  1095.                     pEnumHostsResponseMsg->pAddressSender->Duplicate( &g_pEnumedSessionHostAddr );
  1096.  
  1097.                 // Duplicate pEnumHostsResponseMsg->pAddressDevice in g_pEnumedSessionDeviceAddr.
  1098.                 if( pEnumHostsResponseMsg->pAddressDevice )
  1099.                     pEnumHostsResponseMsg->pAddressDevice->Duplicate( &g_pEnumedSessionDeviceAddr );
  1100.  
  1101.                 // Copy pEnumHostsResponseMsg->pApplicationDescription to g_pEnumedSessionAppDesc
  1102.                 g_pEnumedSessionAppDesc = new DPN_APPLICATION_DESC;
  1103.                 ZeroMemory( g_pEnumedSessionAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1104.                 memcpy( g_pEnumedSessionAppDesc, pEnumHostsResponseMsg->pApplicationDescription,
  1105.                         sizeof(DPN_APPLICATION_DESC) );
  1106.                 if( pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName )
  1107.                 {
  1108.                     g_pEnumedSessionAppDesc->pwszSessionName = new WCHAR[ wcslen(pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName)+1 ];
  1109.                     wcscpy( g_pEnumedSessionAppDesc->pwszSessionName,
  1110.                             pEnumHostsResponseMsg->pApplicationDescription->pwszSessionName );
  1111.                 }
  1112.  
  1113.                 SetEvent( g_hEnumHostEvent );
  1114.             }
  1115.             break;
  1116.         }
  1117.  
  1118.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  1119.         {
  1120.             PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
  1121.             pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
  1122.  
  1123.             if( pAsyncOpCompleteMsg->hAsyncOp == g_hEnumAsyncOp )
  1124.             {
  1125.                 if( WAIT_TIMEOUT == WaitForSingleObject( g_hEnumHostEvent, 0 ) )
  1126.                 {
  1127.                     MessageBox( g_hDlg, TEXT("No session found."), g_strAppName, MB_OK );
  1128.                     SAFE_RELEASE( g_pEnumedSessionDeviceAddr );
  1129.                     KillTimer( g_hDlg, TIMER_WAIT_HOSTS_RESPONSE );
  1130.                     g_hEnumAsyncOp = NULL;
  1131.                 }
  1132.  
  1133.                 g_hEnumHostEvent = NULL;
  1134.             }
  1135.             break;
  1136.         }
  1137.  
  1138.         case DPN_MSGID_CREATE_PLAYER:
  1139.         {
  1140.             HRESULT hr;
  1141.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1142.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  1143.  
  1144.             // Create a new and fill in a APP_PLAYER_INFO
  1145.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1146.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1147.             pPlayerInfo->lRefCount   = 1;
  1148.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1149.  
  1150.             // Get the peer info and extract its name
  1151.             DWORD dwSize = 0;
  1152.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1153.             hr = DPNERR_CONNECTING;
  1154.             
  1155.             // GetPeerInfo might return DPNERR_CONNECTING when connecting, 
  1156.             // so just keep calling it if it does
  1157.             while( hr == DPNERR_CONNECTING ) 
  1158.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );                                
  1159.                 
  1160.             if( hr == DPNERR_BUFFERTOOSMALL )
  1161.             {
  1162.                 pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1163.                 ZeroMemory( pdpPlayerInfo, dwSize );
  1164.                 pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1165.                 
  1166.                 hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  1167.                 if( SUCCEEDED(hr) )
  1168.                 {
  1169.                     // This stores a extra TCHAR copy of the player name for 
  1170.                     // easier access.  This will be redundent copy since DPlay 
  1171.                     // also keeps a copy of the player name in GetPeerInfo()
  1172.                     DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1173.                                                        pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );    
  1174.                                                        
  1175.                     if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  1176.                         g_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  1177.                 }
  1178.  
  1179.                 SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1180.             }
  1181.                 
  1182.             // Tell DirectPlay to store this pPlayerInfo 
  1183.             // pointer in the pvPlayerContext.
  1184.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1185.  
  1186.             // Update the number of active players, and 
  1187.             // post a message to the dialog thread to update the 
  1188.             // UI.  This keeps the DirectPlay message handler 
  1189.             // from blocking
  1190.             InterlockedIncrement( &g_lNumberOfActivePlayers );
  1191.             if( g_hDlg != NULL )
  1192.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  1193.  
  1194.             break;
  1195.         }
  1196.  
  1197.         case DPN_MSGID_DESTROY_PLAYER:
  1198.         {
  1199.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1200.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1201.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1202.  
  1203.             PLAYER_LOCK();                  // enter player context CS
  1204.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1205.             PLAYER_UNLOCK();                // leave player context CS
  1206.  
  1207.             // Update the number of active players, and 
  1208.             // post a message to the dialog thread to update the 
  1209.             // UI.  This keeps the DirectPlay message handler 
  1210.             // from blocking
  1211.             InterlockedDecrement( &g_lNumberOfActivePlayers );
  1212.             if( g_hDlg != NULL )
  1213.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  1214.  
  1215.             break;
  1216.         }
  1217.  
  1218.         case DPN_MSGID_HOST_MIGRATE:
  1219.         {
  1220.             PDPNMSG_HOST_MIGRATE pHostMigrateMsg;
  1221.             pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer;
  1222.  
  1223.             // Check to see if we are the new host
  1224.             if( pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer )
  1225.                 SetWindowText( g_hDlg, TEXT("AddressOverride (Host)") );
  1226.             break;
  1227.         }
  1228.  
  1229.         case DPN_MSGID_TERMINATE_SESSION:
  1230.         {
  1231.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1232.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1233.  
  1234.             g_hrDialog = DPNERR_CONNECTIONLOST;
  1235.             EndDialog( g_hDlg, 0 );
  1236.             break;
  1237.         }
  1238.  
  1239.         case DPN_MSGID_RECEIVE:
  1240.         {
  1241.             PDPNMSG_RECEIVE pReceiveMsg;
  1242.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1243.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1244.             if( NULL == pPlayerInfo )
  1245.                 break;
  1246.  
  1247.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1248.             if( pMsg->dwType == GAME_MSGID_WAVE )
  1249.             {
  1250.                 // This message is sent when a player has waved to us, so 
  1251.                 // post a message to the dialog thread to update the UI.  
  1252.                 // This keeps the DirectPlay threads from blocking, and also
  1253.                 // serializes the recieves since DirectPlayMessageHandler can
  1254.                 // be called simultaneously from a pool of DirectPlay threads.
  1255.                 PostMessage( g_hDlg, WM_APP_DISPLAY_WAVE, pPlayerInfo->dpnidPlayer, 0 );
  1256.             }
  1257.             break;
  1258.         }
  1259.  
  1260.         case DPN_MSGID_CONNECT_COMPLETE:
  1261.         {
  1262.             PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
  1263.             pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
  1264.  
  1265.             // Set m_hrConnectComplete, then set an event letting 
  1266.             // everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
  1267.             // has been handled
  1268.             g_hrConnectComplete = pConnectCompleteMsg->hResultCode;
  1269.             SetEvent( g_hConnectCompleteEvent );
  1270.             break;
  1271.         }
  1272.     }
  1273.  
  1274.     return S_OK;
  1275. }
  1276.  
  1277.  
  1278.  
  1279.  
  1280. //-----------------------------------------------------------------------------
  1281. // Name: WaveToAllPlayers()
  1282. // Desc: Send a app-defined "wave" DirectPlay message to all connected players
  1283. //-----------------------------------------------------------------------------
  1284. HRESULT WaveToAllPlayers()
  1285. {
  1286.     // This is called by the dialog UI thread.  This will send a message to all
  1287.     // the players or inform the player that there is no one to wave at.
  1288.     if( g_lNumberOfActivePlayers == 1 )
  1289.     {
  1290.         MessageBox( NULL, TEXT("No one is around to wave at! :("), 
  1291.                     TEXT("AddressOverride"), MB_OK );
  1292.     }
  1293.     else
  1294.     {
  1295.         // Send a message to all of the players
  1296.         GAMEMSG_GENERIC msgWave;
  1297.         msgWave.dwType = GAME_MSGID_WAVE;
  1298.  
  1299.         DPN_BUFFER_DESC bufferDesc;
  1300.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_GENERIC);
  1301.         bufferDesc.pBufferData  = (BYTE*) &msgWave;
  1302.  
  1303.         // DirectPlay will tell via the message handler 
  1304.         // if there are any severe errors, so ignore any errors 
  1305.         DPNHANDLE hAsync;
  1306.         g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1307.                        0, NULL, &hAsync, DPNSEND_NOLOOPBACK | DPNSEND_GUARANTEED );
  1308.     }
  1309.  
  1310.     return S_OK;
  1311. }
  1312.  
  1313.  
  1314.  
  1315.  
  1316. //-----------------------------------------------------------------------------
  1317. // Name: AppendTextToEditControl()
  1318. // Desc: Appends a string of text to the edit control
  1319. //-----------------------------------------------------------------------------
  1320. VOID AppendTextToEditControl( HWND hDlg, TCHAR* strNewLogLine )
  1321. {
  1322.     static TCHAR strText[1024*10];
  1323.  
  1324.     HWND hEdit = GetDlgItem( hDlg, IDC_LOG_EDIT );
  1325.     SendMessage( hEdit, WM_SETREDRAW, FALSE, 0 );
  1326.     GetWindowText( hEdit, strText, 1024*9 );
  1327.  
  1328.     _tcscat( strText, strNewLogLine );
  1329.  
  1330.     int nSecondLine = 0;
  1331.     if( SendMessage( hEdit, EM_GETLINECOUNT, 0, 0 ) > 9 )
  1332.         nSecondLine = (int)SendMessage( hEdit, EM_LINEINDEX, 1, 0 );
  1333.  
  1334.     SetWindowText( hEdit, &strText[nSecondLine] );
  1335.  
  1336.     SendMessage( hEdit, WM_SETREDRAW, TRUE, 0 );
  1337.     InvalidateRect( hEdit, NULL, TRUE );
  1338.     UpdateWindow( hEdit );
  1339. }
  1340.  
  1341.  
  1342.  
  1343.